Skip to content

FEAT: Implement cl.options.describe_option.#877

Open
genedan wants to merge 7 commits into
mainfrom
#856-init-cleanup
Open

FEAT: Implement cl.options.describe_option.#877
genedan wants to merge 7 commits into
mainfrom
#856-init-cleanup

Conversation

@genedan
Copy link
Copy Markdown
Collaborator

@genedan genedan commented May 28, 2026

Summary of Changes

Implement cl.options.describe_option() to mirror the behavior of pd.describe_option.

Also renamed options parameter to pat in the options functions to match the pandas API.

Related GitHub Issue(s)

#866

Additional Context for Reviewers

The regex is complicated. I did ask Claude to write it and explain (see below). I summarized the match within the function but I can also add this detailed piece-by-piece explanation if you think it's needed.

  - ^{option}: — matches the option name (e.g. ARRAY_BACKEND:) at the start of a line, thanks to re.MULTILINE
  - \s* — allows optional whitespace between the colon and the type
  - (\S+) — captures the type annotation (e.g. str, bool, list) — one or more non-whitespace characters, in capture group 1
  - \n — matches the newline ending that first line
  - ((?:[ \t]+.+\n?)+) — captures the description block in group 2:
    - [ \t]+ — one or more spaces or tabs (the indentation that marks a description line)
    - .+ — one or more characters (the description text)
    - \n? — optional newline at the end of the line
    - (?:...)+ — the whole thing repeats one or more times to capture multi-line descriptions, with (?:...) being a non-capturing group so it doesn't interfere with capture group 2 

Here's what the output should look like to help:

cl.options.describe_option("AUTO_SPARSE")
AUTO_SPARSE : bool
      Controls whether chainladder automatically converts a triangle's backing array to a sparse representation
      when it would be memory-efficient to do so.
      [default: True] [currently: True]
cl.options.describe_option('AUTO_SPARSE|ARRAY_BACKEND')
ARRAY_BACKEND : str
    The default array backend for chainladder.
    [default: numpy] [currently: numpy]
AUTO_SPARSE : bool
    Controls whether chainladder automatically converts a triangle's backing array to a sparse representation
    when it would be memory-efficient to do so.
    [default: True] [currently: True]
  • I passed tests locally for both code (uv run pytest) and documentation changes (uv run jb build docs --builder=custom --custom-builder=doctest)

Note

Medium Risk
Public options API signature changes (option → pat) affect how users configure ARRAY_BACKEND and related globals; behavior is mostly backward compatible via deprecation warnings.

Overview
Adds cl.options.describe_option() in the style of pandas: it prints or returns option docs parsed from the Options class docstring, plus [default: …] and [currently: …] values. pat supports regex (e.g. AUTO_SPARSE|ARRAY_BACKEND) or an empty string for all options; _print_desc=False returns the text instead of printing.

get_option / set_option / reset_option now take pat as the primary argument (positional or keyword). The old option= keyword still works with a FutureWarning; supplying both pat and option raises TypeError. Shared _resolve_pat handles this, and missing required pat / value (via an _UNSET sentinel on set_option) raises clearer TypeError messages.

set_option only runs the ARRAY_PRIORITY + cupy deprecation path when value is a list. Tests cover describe output, deprecation, validation errors, invalid regex, and empty docstring fallback.

Reviewed by Cursor Bugbot for commit af01a1a. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

❌ Patch coverage is 94.66667% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.24%. Comparing base (25e1192) to head (af01a1a).

Files with missing lines Patch % Lines
chainladder/__init__.py 94.52% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #877      +/-   ##
==========================================
+ Coverage   88.16%   88.24%   +0.07%     
==========================================
  Files          87       87              
  Lines        4952     5010      +58     
  Branches      629      641      +12     
==========================================
+ Hits         4366     4421      +55     
- Misses        443      444       +1     
- Partials      143      145       +2     
Flag Coverage Δ
unittests 88.24% <94.66%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0444076. Configure here.

Comment thread chainladder/__init__.py Outdated
@kennethshsu
Copy link
Copy Markdown
Collaborator

Do we need proper deprecation cycle to go from options to pat? I've personally never used this, but I think we should be cautious.

@genedan
Copy link
Copy Markdown
Collaborator Author

genedan commented May 29, 2026

Yeah that's a public API change. So would #874. I'll rename the parameters back to options and then we can mark the argument name change and #874 for milestone 1.0, and then add a warning. For #855 we can decide on how long those warnings will stick around.

I wonder if not-so-big changes like the name of a parameter would warrant a major bump (let's say, the next time we do this, does the package have to be 2.0?). I think it would actually, if we wanted to be strict about things, since backwards-incompatible changes are what warrant a major bump.

@henrydingliu
Copy link
Copy Markdown
Collaborator

we could also be verbose and make old names into properties that return the new name.

@kennethshsu
Copy link
Copy Markdown
Collaborator

I know we haven't quite figure out deprecation cycle rules, but I think we should at least give warning for a cycle (a quarter?), then move on at the next release (6 mos after?) at the minimum. I also don't want to overcomplicate this but I think this is good practice.

The semantic version is not a big issue, but probably safer to go up in minor (2nd digit) instead of fix (last digit).

@kennethshsu
Copy link
Copy Markdown
Collaborator

@genedan @henrydingliu how are we moving forward with this? Who are we waiting on?

@genedan
Copy link
Copy Markdown
Collaborator Author

genedan commented Jun 3, 2026

You're waiting on me lol. Still working on getting the deprecation warning in there.

@genedan
Copy link
Copy Markdown
Collaborator Author

genedan commented Jun 3, 2026

I added some deprecation logic, via the _resolve_pat() function which still allows option to be used but warns the user if they do it. It's more involved than I'd like, the reason why is because temporarily allowing two parameters to do the same thing leads to lots of combos that need to be handled (triggering errors when none are supplied but are required, or when both are supplied accidentally, or when both or optional, etc.).

I don't think we should discard _resolve_pat() after we change the parameter name for good. We could generalize it to handle deprecation/renaming of argument names.

@kennethshsu
Copy link
Copy Markdown
Collaborator

That's probably how I would've done it too.

And sorry for the merge conflict, can you resolve?

@henrydingliu can you take a look at this one too and see if you agree/approve the implementation? I'd like a second set of eyes on this one just because I don't feel my review is good enough and you'll probably have more comments.

genedan added 2 commits June 3, 2026 16:29
# Conflicts:
#	chainladder/__init__.py
#	chainladder/utils/tests/test_utilities.py
@henrydingliu
Copy link
Copy Markdown
Collaborator

i have a more meta question before reviewing the code in more detail. did we already screw the pooch with the previous PR on this campaign? i.e. users, like our own docs, are already having to make (very slight) changes.

@genedan
Copy link
Copy Markdown
Collaborator Author

genedan commented Jun 3, 2026

I think it's revealed some weaknesses in maintaining the docs. #906 will help a lot. If the warnings in #881 work, we should see them the next time we publish the docs in the place where we set cupy:

https://chainladder-python.readthedocs.io/stable/user_guide/triangle.html#other-parameters

And then when once the deprecation happens, the notebook will fail to execute and we'll discover that we need to update that portion of the docs.

I think the other place where we set the options:

https://chainladder-python.readthedocs.io/stable/user_guide/methods.html

Doesn't use keyword arguments, so I don't think it'll be affected.

We don't have an API ref page for Options in the docs, should I go ahead and make one? The docstrings have deprecation warnings in them that are supposed to render warning boxes, so we'll be able to test whether they show up in the docs.

@henrydingliu
Copy link
Copy Markdown
Collaborator

I think it's revealed some weaknesses in maintaining the docs. #906 will help a lot. If the warnings in #881 work, we should see them the next time we publish the docs in the place where we set cupy:

what i'm saying is, if we have already introduced breaking changes in that PR, do we need to revert prior to the 0.9.3. or, do we just power through and allow a bit more breaking changes to make this PR simpler?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants